package cn.wen.forum.common.Filter;

import cn.wen.forum.common.config.RequestWrapper;
import cn.wen.forum.common.config.ResponseWrapper;
import cn.wen.forum.common.util.RedisUtils;
import cn.wen.forum.config.JWTConfig;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * @ClassName ForumFilter
 * @Author By wen
 * @Description 请求过滤器
 * @Date 2023/3/20 9:15
 * @Version 2.0
 */
@Component
public class ForumFilter implements Filter {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 项目初始化时解析http请求日志位置
     * 生成日志文件
     * 初始化PrintWriter
     *
     * @throws IOException
     */
    @Override
    public void init(FilterConfig filterConfig){
        logger.info("--------项目启动-----------");
    }

    /**
     * 过滤器实现token的验证
     * @param servletRequest
     * @param servletResponse
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        JSONObject jsonObject = new JSONObject();
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        RequestWrapper requestWrapper = new RequestWrapper(request);
        ResponseWrapper responseWrapper = new ResponseWrapper(response);

        String body = requestWrapper.getBody();
        String url = ((HttpServletRequest)servletRequest).getRequestURI();

        String method = ((HttpServletRequest) servletRequest).getMethod();
        logger.info("=============请求URI形式：["+method+"]================");
        logger.info("请求URI路径：["+url+"]  请求参数：["+ body+ "]");

        boolean isIntercept = true;
        // 放行get请求
        if(method.matches("GET")){
            isIntercept = false;
            logger.info("请求URI路径为GET方法，被放行");
        }
        // 放行首页请求帖子数据
        if("/forum/postList".equals(url)){
            isIntercept = false;
            logger.info("请求URI路径被放行");
        } else{
            //其他请求：需要登录，验证token
            String token = request.getHeader("Authorization");
            if(StringUtils.isNotBlank(token)){
                //token验证结果
                String userKey = JWTConfig.parseJWT(request);
                if(userKey == null){
                    //验证失败
                    jsonObject.put("errorMsg","用户信息验证失败，请尝试重新登录！");
                } else{
                    Object cacheObject = redisUtils.getCacheObject(userKey);
                    if(cacheObject != null){
                        logger.info("请求URI路径包含用户JWT信息，被放行");
                        isIntercept = false;
                    } else{
                        jsonObject.put("errorMsg","用户登录信息过期，请尝试重新登录！");
                    }
                }
            }else{
                //token为空的返回
                jsonObject.put("errorMsg","用户未登录，请登录后操作！");
            }
        }

        if(isIntercept){
            // 拦截请求
            logger.warn("========请求URI路径被拦截=========["+jsonObject.toString()+"]");
            servletResponse.setContentType("application/json");
            //设置响应的编码
            servletResponse.setCharacterEncoding("utf-8");
            //响应
            jsonObject.put("errorMsg","用户未登录，请登录后操作！");
            jsonObject.put("code","401");
            //response.setStatus(401);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(jsonObject.toString());
        } else{
            // 放行
            chain.doFilter(requestWrapper,responseWrapper);
            // 请求参数重新写入流中
            byte[] content = responseWrapper.getContent();
            //注意 此处是servletResponse 不是responseWrapper,写responseWrapper的话 依旧响应不了
            servletResponse.setContentLength(-1);
            ServletOutputStream outputStream = servletResponse.getOutputStream();
            outputStream.write(content);
            outputStream.flush();
            outputStream.close();
            return;
        }
    }
}
